package com.youlu.campus.web.community.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.base.order.GoodsInfo;
import com.youlu.campus.base.order.enums.OrderPayTypeEnum;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.VO.PlaceOrderReq;
import com.youlu.campus.entity.VO.req.PlaceOrderVO;
import com.youlu.campus.entity.VO.req.UserCaQuery;
import com.youlu.campus.entity.ca.GiftCaInfo;
import com.youlu.campus.entity.course.dto.GoodsOrderDTO;
import com.youlu.campus.entity.course.vo.UserActivityDeductionVo;
import com.youlu.campus.entity.domain.ActivityRewadDomain;
import com.youlu.campus.entity.domain.UserCaDomain;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.activity.ActivityTaskService;
import com.youlu.campus.service.activity.impl.ActivityPayConfigService;
import com.youlu.campus.service.ca.CaMaterialConfigService;
import com.youlu.campus.service.ca.CaPinYinService;
import com.youlu.campus.service.cache.CacheActivityService;
import com.youlu.campus.service.cache.CacheCaInfoService;
import com.youlu.campus.service.cache.CacheOrderService;
import com.youlu.campus.service.course.UserActivityDeductionService;
import com.youlu.campus.service.course.WechatPayService;
import com.youlu.campus.service.invite.UserInviteRecordService;
import com.youlu.campus.service.order.OrderInfoTipService;
import com.youlu.campus.service.platform.PlatformConfigService;
import com.youlu.campus.service.postage.PostageTemplateService;
import com.youlu.campus.service.visitor.UserInfoExtendService;
import com.youlu.campus.service.wechat.WechatConfigInfoService;
import com.youlu.campus.service.wechat.WechatMerchantConfigService;
import com.youlu.campus.service.wechatpay.WechatPayCacheService;
import com.youlu.campus.service.university.UniversityService;
import com.youlu.campus.web.common.base.RequestContext;
import com.youlu.campus.web.community.service.WechatMiniCaService;
import com.youlu.campus.web.order.entity.OrderPO;
import com.youlu.campus.web.order.service.OrderBaseService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.youlu.campus.web.ca.service.impl.UserCaInfoServiceImpl.USER_ORDER_PAY;

@Slf4j
@Service
public class WechatMiniCaServiceImpl extends OrderBaseService implements WechatMiniCaService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserInfoExtendService userInfoExtendService;
    @Autowired
    private ActivityPayConfigService activityPayConfigService;
    @Autowired
    private PostageTemplateService postageTemplateService;
    @Autowired
    private CacheActivityService cacheActivityService;
    @Autowired
    private WechatConfigInfoService wechatConfigInfoService;

    @Autowired
    private PlatformConfigService platformConfigService;
    @Autowired
    private CacheCaInfoService cacheCaInfoService;
    @Autowired
    private OrderInfoTipService orderInfoTipService;
    @Autowired
    private WechatMerchantConfigService wechatMerchantConfigService;
    @Autowired
    private StringRedisTemplate orderRedisTemplate;
    @Autowired
    private ActivityService activityService;
    @Autowired
    private WechatPayCacheService wechatPayCacheService;

    @Autowired
    private CacheOrderService cacheOrderService;
    @Autowired
    private WechatPayService wechatPayService;

    @Autowired
    private UserInviteRecordService userInviteRecordService;

    @Autowired
    private ActivityTaskService activityTaskService;


    @Autowired
    private CaPinYinService caPinYinService;

    @Autowired
    private UniversityService universityService;

    @Autowired
    private UserActivityDeductionService userActivityDeductionService;

    @Autowired
    private CaMaterialConfigService caMaterialConfigService;

    private static final Integer NUM = 1;


    @Override
    public UserCaDomain getUserCaInfos(@NotNull UserCaQuery req) {
        log.info(":>>> 开始获取纸质版证书信:{}", JSON.toJSON(req));
        UserCaDomain userCaDomain = new UserCaDomain();
        UserInfoExtend extend = userInfoExtendService.findByUserIdAndAppId(req.getCurrentUser());
        if (Objects.nonNull(extend)) {
            userCaDomain.setName(extend.getName());
            userCaDomain.setMobile(extend.getMobile());
            userCaDomain.setArea(extend.getArea());
            userCaDomain.setCity(extend.getCity());
            userCaDomain.setProvince(extend.getProvince());
            userCaDomain.setUniversityId(extend.getUniversityId());
            userCaDomain.setUniversityName(extend.getUniversityName());
            userCaDomain.setFullAddress(extend.getAddress());
        }
//        PayConfigPage payConfigPage = cachePayConfigService.findByActivityId(req.getActivityId());
//        if (Objects.nonNull(payConfigPage)) {
//            userCaDomain.setPreOrderDesc(payConfigPage.getCertificateDesc());
//        }
        PayConfigPage payConfigPage = activityPayConfigService.findByActivityId(req.getActivityId(), 2);
        if (Objects.nonNull(payConfigPage.getPayButtonConfigList())) {
            List<PayButtonConfigPage> payButtonConfigList = payConfigPage.getPayButtonConfigList();
            for (PayButtonConfigPage payButtonConfigPage : payButtonConfigList) {
                if (payButtonConfigPage.getCaType().equals(req.getCaType())) {
                    userCaDomain.setPreOrderDesc(payButtonConfigPage.getItemDetail());
                    break;
                }
            }
        }
        ActivityInfo activityInfo = cacheActivityService.findById(req.getActivityId());
        if (Objects.nonNull(activityInfo)) {
            userCaDomain.setReceiveAddressTips(activityInfo.getReceiveAddressTips());
        }
        Query queryGroup = new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and(
                "taskBizType").is(req.getCaType()).and("deleted").ne(Boolean.TRUE));
        CaGroupInfo groupInfo = mongoTemplate.findOne(queryGroup, CaGroupInfo.class);
        if (Objects.isNull(groupInfo)) {
            throw new BusinessException("未配置证书序列");
        }
        Query queryCa = new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and(
                "caGroupInfoId").is(groupInfo.getId()));

        if (!CollectionUtils.isEmpty(req.getCaIds())) {
            queryCa.addCriteria(Criteria.where("id").in(req.getCaIds()));
        }
        queryCa.addCriteria(Criteria.where("deleted").is(Boolean.FALSE));
        queryCa.with(Sort.by(Sort.Direction.DESC, "priority"));
        List<CaInfo> caInfoList = mongoTemplate.find(queryCa, CaInfo.class);
        if (CollectionUtils.isEmpty(caInfoList)) {
            throw new BusinessException("未配置证书序列等级");
        }

        UserActivityDeductionVo vo = userActivityDeductionService.getUserDeductionVo(req.getUserId(), req.getActivityId());
        boolean deductionExpire = vo.getHasDeduction() && vo.getDiffTime() > 0;
        // 设置扣减信息
        List<CaInfo> caInfos =
                caInfoList.stream().filter(caInfo -> caInfo.getLevel().equals(req.getCaLevel()))
                        .map(item -> {
                            item.setDeductionExpire(deductionExpire);
                            if (deductionExpire) {
                                item.setDeductionMoney(vo.getMoney());
                            }
                            //不允许超卖
                            if (!item.getCanOverbought()) {
                                List<String> itemMaterialIdList = item.getItemMaterialList();
                                if (!org.springframework.util.CollectionUtils.isEmpty(itemMaterialIdList)) {
                                    //不允许超卖情况
                                    long count =
                                            itemMaterialIdList.stream().filter(itemMaterialId -> caMaterialConfigService.overbought(itemMaterialId)).count();
                                    if (count > 0) {
                                        item.setOnSale(Boolean.FALSE);
                                    } else {
                                        List<CaMaterialConfig> materialList =
                                                caMaterialConfigService.findByCaMaterialIdList(itemMaterialIdList);
                                        long stockCountZero =
                                                materialList.stream().filter(caMaterialConfig -> (caMaterialConfig.getStockCount() - caMaterialConfig.getSoldCount()) <= 0).count();
                                        if (stockCountZero > 0) {
                                            item.setOnSale(Boolean.FALSE);
                                        }
                                    }
                                }
                            }
                            return item;
                        }).collect(Collectors.toList());
        userCaDomain.setCaInfos(caInfos);
        userCaDomain.setDeductionInfo(vo);

        return userCaDomain;
    }

    @Override
    public UserCaDomain getActivtyOrderItemInfo(@NotNull UserCaQuery req) {
        return null;
    }

    /**
     * 下单
     *
     * @param req
     * @param userPO
     * @return
     */
    @Override
    public OrderInfo placeOrder(PlaceOrderVO req, UserPO userPO) {
        log.info(":>>> 开始处理用户下单接口:{},用户:{}", JSON.toJSONString(req), JSON.toJSONString(userPO));
        if (Objects.isNull(req) || StringUtils.isBlank(req.getActivityId()) || StringUtils.isBlank(req.getCaType()) || org.springframework.util.CollectionUtils.isEmpty(req.getCaIds())) {
            log.error(":>>> 用户下单参数错误:活动、业务类型、证书ID为空");
            throw new BusinessException("用户下单参数错误");
        }

        String orderNo = super.generateOrderNo("证书");
        log.info(":>>> 生成的证书订单编号:{}", orderNo);
        if (super.resubmit(3L, RequestContext.getUserId(), orderNo)) {
            log.info(":>>> 有已经待支付的订单,请不要重复支付");
            throw new BusinessException("请勿重复发起支付~");
        }
        checkDuplicateOrder(req, userPO);
        ActivityInfo activityInfo = cacheActivityService.findById(req.getActivityId());
        Date date = new Date();
        OrderInfo orderInfo = new OrderInfo();
        WechatConfigInfo wechatConfigInfo = wechatConfigInfoService.find(userPO.getAppId());
        if (Objects.isNull(wechatConfigInfo) || Objects.isNull(wechatConfigInfo.getMerchantIds()) || CollectionUtils.isEmpty(wechatConfigInfo.getMerchantIds())) {
            log.error(":>>> 微信公众号配置错误:{}", userPO.getAppId());
            throw new BusinessException("当前支付人数多,稍后重试");
        }
        PayConfigPage payConfig = activityPayConfigService.findByActivityId(req.getActivityId(), 2);
        PostageTemplate postageTemplate = null;
        if (Objects.nonNull(payConfig) && StringUtils.isNotBlank(payConfig.getPostageTemplateId())) {
            postageTemplate = postageTemplateService.findOne(payConfig.getPostageTemplateId());
        }

        UserInfoExtend extend = userInfoExtendService.findByUserIdAndAppId(userPO);
        if (Objects.isNull(extend) || extend.checkUserInfo()) {
            log.error("【小程序下单】WechatMiniCaService.placeOrder 用户姓名或 学校不能为空", userPO.getId());
            throw new BusinessException("证书上姓名学校不能为空，请先去完善个个人信息");
        }
        orderInfo.setName(extend.getName());

        if (StringUtils.isBlank(extend.getMobile())) {
            orderInfo.setMobile(userPO.getMobile());
        } else {
            orderInfo.setMobile(extend.getMobile());
        }
        orderInfo.setProvince(extend.getProvince());
        orderInfo.setCity(extend.getCity());
        orderInfo.setArea(extend.getArea());
        orderInfo.setAddress(extend.getAddress());
        orderInfo.setUniversityId(extend.getUniversityId());
        //需要英文名称
        if (ActivityInfo.DIGITAL_ENGLISH_CA.equals(activityInfo.getDigitalCaType())) {
            if (StringUtils.isNotBlank(extend.getEnName())) {
                orderInfo.setCaPrintName(extend.getEnName());
            } else {
                String pinYinName = caPinYinService.getPinYinNameByUserId(req.getActivityId(), extend);
                if (StringUtils.isNotBlank(pinYinName)) {
                    userPO.setEnName(pinYinName);
                    this.userInfoExtendService.saveOrUpdate(userPO);
                    orderInfo.setCaPrintName(pinYinName);
                }
            }
            UniversityInfo universityInfo = universityService.get(extend.getUniversityId());
            if (Objects.nonNull(universityInfo)) {
                if (StringUtils.isNotBlank(universityInfo.getEnName())) {
                    orderInfo.setUniversityName(universityInfo.getEnName());
                }
            }
        } else {
            orderInfo.setCaPrintName(extend.getName());
            orderInfo.setUniversityName(extend.getUniversityName());
        }
        Date currentDate = new Date();
        List<PayButtonConfigPage> payButtonConfigList = payConfig.getPayButtonConfigList();
        long count =
                payButtonConfigList.stream().filter(payButtonConfig -> PayButtonConfigPage.PAPER_CERTIFICATE.equals(payButtonConfig.getButtonType()) &&
                        payButtonConfig.getCaType().equals(req.getCaType()) && currentDate.before(payButtonConfig.getEndTime())).count();
        if (count == 0) {
            log.error("用户->{}参与活动->{} 类型 {} 下单已超时", userPO.getId(), activityInfo.getName(), req.getCaType());
            throw new BusinessException("领取已结束，无法提交订单");
        }
        checkUserOrder(userPO.getId(), activityInfo.getId(), orderInfo.getTaskBizType());
        orderInfo.setOrderNo(orderNo);
        orderInfo.setCreatedTime(date);
        orderInfo.setStatus("0");
        orderInfo.setActivityId(req.getActivityId());
        orderInfo.setAppId(userPO.getAppId());
        orderInfo.setOpenId(userPO.getOpenId());
        orderInfo.setPlatform(userPO.getCurrentPlatform());
        orderInfo.setTaskBizType(req.getCaType());
        PlatformConfig platformConfig = platformConfigService.find();
        Integer price = 0;
        Integer num = 0;
        Integer totalPrice = 0;
        Integer expressFee = 0;
        Integer discountPrice = 0;
        Integer deductionFee = 0;
        String expressTips = "";
        //初始化是否包含有礼品订单
        List<Integer> giftList = Lists.newArrayListWithCapacity(req.getCaIds().size());
        UserActivityDeductionVo vo = userActivityDeductionService.getUserDeductionVo(req.getUserId(), req.getActivityId());
        boolean deductionExpire = vo.getHasDeduction() && vo.getDiffTime() > 0;
        for (String caId : req.getCaIds()) {
            CaInfo caInfo = cacheCaInfoService.findById(caId);
            if (Objects.isNull(caInfo)) {
                log.error(":>>> 证书不存在:{}", caId);
                throw new BusinessException("证书不存在");
            }
            String oorderNo = super.generateOrderNo("证书子订单");
            OOrderInfo oOrderInfo = buildOOrderInfo(caInfo, userPO, req.getActivityId(), orderNo, oorderNo, false);
            discountPrice = discountPrice + (caInfo.getOriginalPrice() == null ? caInfo.getPrice() :
                    caInfo.getOriginalPrice() - caInfo.getPrice());
            orderInfo.setTitle(caInfo.getName());
            if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
                orderInfo.setImageUrl(caInfo.getCertificateImage());
            } else {
                orderInfo.setImageUrl(caInfo.getCertificateImages()[0]);
            }
            // 获取到证书-即证书
            if (!oOrderInfo.getCaGift()) {
                giftList.add(1);
            }
            orderInfo.setGift(caInfo.getGift());
            price = price + caInfo.getPrice();
            Integer e = 0;
            Integer extraFee = 0;
            if (caInfo.getPrice() > 1) {
                HashMap<String, Integer> ee = getOrderExpreeFee(postageTemplate, orderInfo.getProvince(),
                        caInfo.getExpressFee());
                log.info(":>>> 邮费项:{}", JSON.toJSONString(ee));
                e = ee.get("fee");
                extraFee = ee.get("extraFee");
            }
            orderInfo.setExtraExpressFee(extraFee);
            totalPrice = totalPrice + caInfo.getPrice() + e + extraFee;
            expressFee = expressFee + e;
            num = num + 1;
            orderInfoTipService.setOOrderTips(orderInfo, platformConfig, oOrderInfo);
            oOrderInfo.setDeductionExpire(deductionExpire);
            if (deductionExpire) {
                oOrderInfo.setDeductionMoney(vo.getMoney());
                totalPrice = totalPrice - vo.getMoney();
                deductionFee += vo.getMoney();
            }
            mongoTemplate.insert(oOrderInfo);
            log.info(":>>> 证书:{} 邮费提示语:{}", caInfo.getId(), caInfo.getExpressFeeTips());
            if (StringUtils.isNotBlank(caInfo.getExpressFeeTips())) {
                expressTips = caInfo.getExpressFeeTips();
            }
            if (Objects.nonNull(caInfo.getGiftItems()) && !org.springframework.util.CollectionUtils.isEmpty(caInfo.getGiftItems())) {
                for (GiftCaInfo c : caInfo.getGiftItems()) {
                    String ooorderNo = super.generateOrderNo("证书子订单");
                    CaInfo caInfoGift = new CaInfo();
                    BeanUtils.copyProperties(c, caInfoGift);
                    OOrderInfo ooOrderInfo = buildOOrderInfo(caInfoGift, userPO, req.getActivityId(), orderNo, ooorderNo, true);
                    mongoTemplate.insert(ooOrderInfo);
                }
            }
        }
        long caCount = giftList.stream().filter(gift -> gift == 1).count();
        log.info("【订单包含证书数量】orderNo - > {} count - > {}", orderNo, caCount);
        if (caCount == 0) {
            orderInfo.setCategory("gift");
        }
        //
        orderInfo.setTotalFee(totalPrice);
        orderInfo.setItemPrice(price);
        orderInfo.setNum(num);
        orderInfo.setExpressFee(expressFee);
        orderInfo.setDiscountFee(discountPrice);
        orderInfo.setDeductionFee(deductionFee);
        orderInfo.setAccountInfoId(userPO.getId());
        orderInfo.setTips(activityInfo.getOrderTips());
        orderInfo.setCreatedTime(new Date());
        orderInfo.setExpressDesc(postageTemplate.getExpressDesc());
        if (StringUtils.isNotBlank(expressTips)) {
            orderInfo.setExpressFeeTips(expressTips);
        } else {
            orderInfo.setExpressFeeTips(postageTemplate.getExpressFeeTips());
        }
        Query query =
                new Query().addCriteria(Criteria.where("userId").is(userPO.getId()).and("activityId").is(req.getActivityId()).and("joined").is(Boolean.TRUE));
        UserParticipateActivityInfo up = mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
        if (Objects.nonNull(up)) {
            if (StringUtils.isBlank(up.getMobile())) {
                orderInfo.setSignUpMobile(orderInfo.getMobile());
            } else {
                orderInfo.setSignUpMobile(up.getMobile());
            }
            if (StringUtils.isBlank(up.getName())) {
                orderInfo.setSignUpName(orderInfo.getName());
            } else {
                orderInfo.setSignUpName(up.getName());
            }

            log.info(":>>> 用户:{} 报名手机号:{},报名姓名:{}", userPO.getId(), up.getMobile(), up.getName());
        }
        // 随机
        String merchantId = wechatConfigInfo.getMerchantIds().get(random(wechatConfigInfo.getMerchantIds().size()));
        WechatMerchantConfig merchant = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        if (Objects.isNull(merchant)) {
            log.error(":>>> 微信配置错误:{} ,商户号不存在,请联系管理员", merchantId);
            throw new BusinessException("微信支付异常,请联系在线客服");
        }
        orderInfo.setMechantId(merchant.getMerchantId());
        orderInfo.setMechantName(merchant.getMerchantName());
        orderInfo = mongoTemplate.insert(orderInfo);
        log.info(":>>> 订单:{},邮费提示语:{},证书配置提示语:{}", orderInfo.getOrderNo(), orderInfo.getExpressFeeTips(), expressTips);
        return orderInfo;
    }

    @Override
    public OrderInfo updateOrder(@NotNull OrderInfo req, UserPO userPO, String platform) {
        log.info(":>>> 用户订单更新:{}", JSON.toJSONString(req));
        Query query = new Query().addCriteria(Criteria.where("orderNo").is(req.getOrderNo()));
        OrderInfo orderInfo = mongoTemplate.findOne(query, OrderInfo.class);
        if (Objects.isNull(orderInfo)) {
            throw new BusinessException("当前订单不存在，不能修改订单");
        }
        String status = orderInfo.getStatus();
        if (Arrays.asList("1", "2", "3", "4", "5").contains(status)) {
            throw new BusinessException("你已经完成支付，请返回查看订单。");
        }
        boolean hasDeduction = orderInfo.getDeductionFee() != null && orderInfo.getDeductionFee() > 0;
        orderInfo.setHasDeduction(hasDeduction);
        if (hasDeduction && "wechat-h5".equals(platform)) {
            if (orderInfo.getDeductionEndDate() != null) {
                orderInfo.setDeductionDiffTime(orderInfo.getDeductionEndDate().getTime() - System.currentTimeMillis());
            } else {
                orderInfo.setDeductionDiffTime(0L);
            }
        }
        ActivityInfo activityInfo = this.activityService.findOne(orderInfo.getActivityId());
        Update update = new Update();
        if (StringUtils.isNotBlank(req.getUniversityId()) && !req.getUniversityId().equals(orderInfo.getUniversityId())) {
            update.set("universityId", req.getUniversityId());
            //需要英文名称
            if (ActivityInfo.DIGITAL_ENGLISH_CA.equals(activityInfo.getDigitalCaType())) {
                Query queryU = new Query().addCriteria(Criteria.where("id").is(req.getUniversityId()));
                UniversityInfo universityInfo = mongoTemplate.findOne(queryU, UniversityInfo.class);
                if (Objects.nonNull(universityInfo)) {
                    if (StringUtils.isNotBlank(universityInfo.getEnName())) {
                        update.set("universityName", universityInfo.getEnName());
                    }
                }
            } else {
                update.set("universityName", req.getUniversityName());
            }
        }
        if (StringUtils.isNotBlank(req.getCity()) && !req.getCity().equals(orderInfo.getCity())) {
            update.set("city", req.getCity());
        }
        if (StringUtils.isNotBlank(req.getArea()) && !req.getArea().equals(orderInfo.getArea())) {
            update.set("area", req.getArea());
        }
        if (StringUtils.isNotBlank(req.getAddress()) && !req.getAddress().equals(orderInfo.getAddress())) {
            update.set("address", req.getAddress());
        }
        if (StringUtils.isNotBlank(req.getRecieveMobile()) && !req.getRecieveMobile().equals(orderInfo.getMobile())) {
            update.set("mobile", req.getRecieveMobile());
        }
        if (StringUtils.isNotBlank(req.getRecieveName()) && !req.getRecieveName().equals(orderInfo.getName())) {
            update.set("name", req.getRecieveName());
        }
        if (StringUtils.isNotBlank(req.getCaPrintName())) {
            update.set("caPrintName", req.getCaPrintName());
        }

        if (StringUtils.isNotBlank(req.getProvince()) && !req.getProvince().equals(orderInfo.getProvince())) {
            //如果订单金额大于1
            if (orderInfo.getTotalFee() > 1) {
                //计算邮费差值更新订单金额
                PayConfigPage payConfig = activityPayConfigService.findByActivityId(req.getActivityId(), 2);
                PostageTemplate postageTemplate = null;
                if (Objects.nonNull(payConfig) && StringUtils.isNotBlank(payConfig.getPostageTemplateId())) {
                    postageTemplate = postageTemplateService.findOne(payConfig.getPostageTemplateId());
                    HashMap<String, Integer> ee = getOrderExpreeFee(postageTemplate, req.getProvince(),
                            orderInfo.getExpressFee());
                    if (ee.get("extraFee") != orderInfo.getExtraExpressFee()) {
                        if (ee.get("extraFee") > orderInfo.getExtraExpressFee()) {
                            update.set("totalFee",
                                    orderInfo.getTotalFee() + (ee.get("extraFee") - orderInfo.getExtraExpressFee()) * orderInfo.getNum());
                        } else {
                            update.set("totalFee",
                                    orderInfo.getTotalFee() - (orderInfo.getExtraExpressFee() - ee.get("extraFee")) * orderInfo.getNum());
                        }
                        update.set("extraExpressFee", ee.get("extraFee"));
                    }
                }
            }
            update.set("province", req.getProvince());
        }
        update.set("updatedTime", new Date());
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        OrderInfo orderModify = this.mongoTemplate.findAndModify(query, update, findAndModifyOptions, OrderInfo.class);
        cacheOrderService.remove(req.getOrderNo(), userPO.getId());
//        update = new Update();
//        if (StringUtils.isNotBlank(req.getCity()) && !req.getCity().equals(orderInfo.getCity())) {
//            update.set("city", req.getCity());
//        }
//        if (StringUtils.isNotBlank(req.getArea()) && !req.getArea().equals(orderInfo.getArea())) {
//            update.set("area", req.getArea());
//        }
//        if (StringUtils.isNotBlank(req.getAddress()) && !req.getAddress().equals(orderInfo.getAddress())) {
//            update.set("address", req.getAddress());
//        }
//        if (StringUtils.isNotBlank(req.getRecieveMobile()) && !req.getRecieveMobile().equals(orderInfo.getMobile())) {
//            update.set("receiveMobile", req.getRecieveMobile());
//        }
//        if (StringUtils.isNotBlank(req.getRecieveName()) && !req.getRecieveName().equals(orderInfo.getName())) {
//            update.set("receiveName", req.getRecieveName());
//        }
//        if (StringUtils.isNotBlank(req.getProvince()) && !req.getProvince().equals(orderInfo.getProvince())) {
//            update.set("province", req.getProvince());
//        }
//        if(StringUtils.isNotBlank(userPO.getId())){
//            mongoTemplate.updateFirst(new Query().addCriteria(Criteria.where("userId").is(userPO.getId())), update,
//                    UserInfoExtend.class);
//        }

        return orderModify;
    }

    /**
     * 付款
     *
     * @param req
     * @param userPO
     * @return
     */
    @Override
    public Object payOrder(ActivityRewadDomain req, UserPO userPO) {
        String pOrderNo = req.getOrderNo();
        Query query = new Query().addCriteria(Criteria.where("orderNo").is(req.getOrderNo()));
        OrderInfo orderInfo = mongoTemplate.findOne(query, OrderInfo.class);
        Date date = new Date();
        log.info(":>>> 支付订单:{}", JSON.toJSONString(req));
        OrderPO orderPO = new OrderPO();
        orderPO.setOrderNo(pOrderNo);
        orderPO.setSource(req.getSource());
        orderPO.setPayType(OrderPayTypeEnum.WX.getCode());
        GoodsInfo goods = new GoodsInfo();
        if (StringUtils.isNotBlank(pOrderNo)) {
            goods.setGoodsName(pOrderNo);
        } else {
            goods.setGoodsName("赞我商品");
        }
        this.orderRedisTemplate.opsForValue().set(String.format(USER_ORDER_PAY, orderInfo.getOrderNo()),
                JSON.toJSONString(orderInfo), 30L, TimeUnit.MINUTES);
        PayConfigPage payConfig = activityPayConfigService.findByActivityId(orderInfo.getActivityId(), 0);
        Date currentDate = new Date();
        List<PayButtonConfigPage> payButtonConfigList = payConfig.getPayButtonConfigList();
        long count =
                payButtonConfigList.stream().filter(payButtonConfig -> PayButtonConfigPage.PAPER_CERTIFICATE.equals(payButtonConfig.getButtonType()) &&
                        payButtonConfig.getCaType().equals(orderInfo.getTaskBizType()) && currentDate.before(payButtonConfig.getEndTime())).count();
        if (count == 0) {
            log.error("用户->{}参与活动->{} 类型 {} 下单已超时", userPO.getId(), orderInfo.getActivityId(), req.getTaskBizType());
            throw new BusinessException("领取已结束，无法提交订单");
        }
        checkUserOrder(userPO.getId(), orderInfo.getActivityId(), orderInfo.getTaskBizType());
        orderPO.setGoods(goods);
        orderPO.setPayPrice(orderInfo.getTotalFee());
        orderPO.setTotalPrice(orderInfo.getTotalFee());
        orderPO.setClientIp(req.getClientIp());
        orderPO.setTransactionId(pOrderNo);
        orderPO.setOpenId(userPO.getOpenId());
        orderPO.setPlatform(userPO.getCurrentPlatform());
        orderPO.setUserPO(req.getUserPO());
        orderPO.setNonceStr("" + date.getTime());
        orderPO.setTimestampStr("" + date.getTime() / 1000);
        orderPO.setAppId(orderInfo.getAppId());
        orderPO.setMerchantId(orderInfo.getMechantId());
        ActivityInfo activityInfo = activityService.findOne(orderInfo.getActivityId());
        GoodsOrderDTO dto = new GoodsOrderDTO();
        dto.setOrderNo(orderPO.getOrderNo());
        dto.setClientIp(orderPO.getClientIp());
        dto.setOpenId(orderPO.getOpenId());
        dto.setGoodsName(orderPO.getOrderNo());
        dto.setPrice(orderPO.getTotalPrice());
        dto.setUserId(userPO.getId());
        dto.setAppId(orderPO.getAppId());
        if (Objects.nonNull(activityInfo) && Objects.nonNull(activityInfo.getMerchantSharingProfit()) && activityInfo.getMerchantSharingProfit().getSharingProfit()) {
            dto.setProfitSharing(Boolean.TRUE);
        }
        WechatConfigInfo wechatConfigInfo = wechatConfigInfoService.find(orderPO.getAppId());
        if (Objects.isNull(wechatConfigInfo) || CollectionUtils.isEmpty(wechatConfigInfo.getMerchantIds())) {
            throw new BusinessException("当前支付人数多,稍后重试");
        }
        String merchantId = wechatConfigInfo.getMerchantIds().get(random(wechatConfigInfo.getMerchantIds().size()));
        WechatMerchantConfig merchant = wechatMerchantConfigService.findByMerchantIdAndDecrypt(merchantId);
        if (Objects.isNull(merchant)) {
            throw new BusinessException("微信支付异常,请联系在线客服");
        }
        merchant.setMerchantId(orderInfo.getMechantId());
        merchant.setMerchantName(orderInfo.getMechantName());
        Triple<Boolean, Object, String> result = wechatPayService.unifiedOrder(dto, merchant, req.getUrl());

        /*
        Map<String, String> result = new HashMap<>();
        //获取预支付参数
        QResult<Map<String, String>> uniOrderResult = super.getUniOrderResult(orderPO);
        log.info(":>>> 获取微信预支付参数结果为:{}", JSON.toJSONString(uniOrderResult));
        // 支付成功
        if (uniOrderResult.code == 0) {
            result = uniOrderResult.data;
            log.info("placeOrder applyReq {} result {}", req, result);
        } else {
            log.info("placeOrder applyReq {} error msg {}", req, uniOrderResult.msg);
        }
        result.put("payFeeType", "1");
        result.put("payDesc", "微信支付");
        log.info(":>>> 微信支付参数为:{}", JSON.toJSONString(result));
        if ("wechat-mini".equals(orderPO.getPlatform())) {
            log.info(":>>> 平台是wechat-mini,设置JS SDK配置");
            WechatH5PayConfigDomain config = activityService.getPayConfig(userPO, req.getUrl(), orderPO.getNonceStr()
                    , orderPO.getTimestampStr());
            result.put("appId", config.getAppId());
            result.put("signature", config.getSignature());
            result.put("nonceStr", config.getNonceStr());
            result.put("timeStamp", config.getTimestamp());
            result.put("jsApiList", JSON.toJSONString(config.getJsApiList()));
        }
        */
        Query queryCache = new Query().addCriteria(Criteria.where("orderNo").is(pOrderNo));
        boolean existC = mongoTemplate.exists(queryCache, WechatPayCache.class);
        if (!existC) {
            WechatPayCache cache = new WechatPayCache();
            cache.setOrderNo(pOrderNo);
            cache.setBizType("mix");
            cache.setType("parent");
            wechatPayCacheService.create(cache);
        }
//        Query queryReward =
//                new Query().addCriteria(Criteria.where("activityId").is(req.getActivityId()).and("userId").is(req
//                .getUserId()).and("rewardReceived").is(Boolean.TRUE));
//        boolean exist = mongoTemplate.exists(queryReward, UserActivityReward.class);
//        log.info(":>>> 用户:{},活动:{},领取状态为:{}", req.getUserId(), req.getActivityId(), exist);
//        if (!exist) {
//            UserActivityReward userActivityReward = new UserActivityReward();
//            userActivityReward.setUserId(req.getUserId());
//            userActivityReward.setActivityId(req.getActivityId());
//            userActivityReward.setOrderNo(pOrderNo);
//            userActivityReward.setRewardReceived(Boolean.FALSE);
//            userActivityReward.setCreatedTime(new Date());
//            mongoTemplate.insert(userActivityReward);
//            log.info(":>>> 用户:{} 订单:{} 未领取,新增未领取记录", req.getUserId(), pOrderNo);
//        }
        return result.getLeft() ? result.getMiddle() : null;
    }

    @Override
    public List<String> getOrders(String activityId) {
        Query query =
                new Query().addCriteria(Criteria.where("activityId").is(activityId).and("status").in(Arrays.asList("1"
                        , "2", "3", "4", "5", "6", "7")));
//        query.with(new Sort(Sort.Direction.DESC, "createdTime")).limit(10);
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        query.limit(10);
        List<OrderInfo> orderInfos = mongoTemplate.find(query, OrderInfo.class);
        List<String> list = orderInfos.stream().map(orderInfo -> {
            String name = orderInfo.getName();
            return name;
        }).collect(Collectors.toList());

        return list;
    }

    private Integer random(int max) {
        if (max == 0) {
            return 0;
        }
        return ThreadLocalRandom.current().nextInt(max);
    }

    private void checkUserOrder(String userId, String activityId, String taskBizType) {
        Query query = new Query();
        query.addCriteria(Criteria.where("accountInfoId").is(userId));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("taskBizType").is(taskBizType));
        query.addCriteria(Criteria.where("status").in(Arrays.asList("1", "2", "3", "4", "5")));
        boolean exists = this.mongoTemplate.exists(query, OrderInfo.class);
        if (exists) {
            log.error("用户->{} 重复购买活动 ->{} 类型 - >{}", userId, activityId, taskBizType);
            throw new BusinessException("您已领取此证书/礼品，请勿重复领取");
        }

    }

    private OOrderInfo buildOOrderInfo(CaInfo caInfo, UserPO userPO,
                                       String activityId, String orderNo,
                                       String oorderNo, boolean gift) {
        OOrderInfo oOrderInfo = new OOrderInfo();
        oOrderInfo.setOrderNo(orderNo);
        oOrderInfo.setOOrderNo(oorderNo);
        oOrderInfo.setCreatedTime(new Date());
        oOrderInfo.setAccountInfoId(userPO.getId());
        if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
            oOrderInfo.setImageUrl(caInfo.getCertificateImage());
        } else {
            oOrderInfo.setImageUrl(caInfo.getCertificateImages()[0]);
        }
        //oOrderInfo.setOverbought(caInfo.getCanOverbought());
        List<String> itemMaterialIdList = caInfo.getItemMaterialList();
        if (CollectionUtils.isNotEmpty(itemMaterialIdList)) {
            String itemMaterialId = itemMaterialIdList.get(0);
            if (!caInfo.getCanOverbought()) {
                Boolean overbought = caMaterialConfigService.overboughtByIdAndNum(itemMaterialId, NUM);
                log.info("商品礼品设置不超卖 itemId:{},num:{},userId:{},是否超卖:{}", caInfo.getId(), NUM, userPO.getId(), overbought);
                if (overbought) {
                    throw new BusinessException("库存不足");
                }
            }
        }
        oOrderInfo.setCaItemType(caInfo.getItemType());
        oOrderInfo.setCaInfo(caInfo);
        oOrderInfo.setItemType("ca");
        oOrderInfo.setItemInfoId(caInfo.getId());
        oOrderInfo.setStatus("0");
        oOrderInfo.setItemTitle(caInfo.getName());
        if (ArrayUtils.isEmpty(caInfo.getCertificateImages())) {
            oOrderInfo.setItemImageUrl(caInfo.getCertificateImage());
        } else {
            oOrderInfo.setItemImageUrl(caInfo.getCertificateImages()[0]);
        }
        oOrderInfo.setSalePrice(caInfo.getPrice());
        oOrderInfo.setItemPrice(caInfo.getOriginalPrice());
        oOrderInfo.setAppId(userPO.getAppId());
        oOrderInfo.setOpenId(userPO.getOpenId());
        oOrderInfo.setExpressFee(caInfo.getExpressFee().toString());
        oOrderInfo.setPlatform(userPO.getCurrentPlatform());
        oOrderInfo.setCaGift(caInfo.getCaGift());
        oOrderInfo.setNum(1);
        oOrderInfo.setOpenId(userPO.getOpenId());
        oOrderInfo.setActivityId(activityId);
        oOrderInfo.setGift(caInfo.getGift());
        oOrderInfo.setStatus("0");
        if (gift) {
            oOrderInfo.setGifted(true);
            oOrderInfo.setSalePrice(0);
            oOrderInfo.setItemPrice(0);
            oOrderInfo.setSalePriceBack(caInfo.getPrice());
            oOrderInfo.setItemPriceBack(caInfo.getOriginalPrice());
            oOrderInfo.setItemPrice(0);
        } else {
            oOrderInfo.setGifted(false);
        }
        return oOrderInfo;
    }


    /**
     * 获取邮费模版
     *
     * @param postageTemplate
     * @param province
     * @param expreeFee
     * @return
     */
    private HashMap<String, Integer> getOrderExpreeFee(PostageTemplate postageTemplate, String province,
                                                       Integer expreeFee) {
        log.info(":>>> 开始获取省:{},邮费:{},模版:{}", province, expreeFee, JSON.toJSONString(postageTemplate));
        HashMap<String, Integer> res = new HashMap<>();
        if (StringUtils.isBlank(province) || Objects.isNull(postageTemplate)) {
            log.error(":>>> 下单参数错误:省或证书邮费配置为空");
            res.put("fee", 0);
            res.put("extraFee", 0);
//            throw new BusinessException("请联系客服领取!");
        }
        Integer fee = 0;
        Integer extraFee = 0;
        Query query = new Query().addCriteria(Criteria.where("postageTemplateId").is(postageTemplate.getId()).and(
                "province").is(province));
        PostageTemplateDetail p = mongoTemplate.findOne(query, PostageTemplateDetail.class);
        log.info(">>> 偏远地区邮费:{}", JSON.toJSONString(p));
        if (Objects.nonNull(p)) {
            extraFee = p.getPrice().intValue();

        }
        if (Objects.nonNull(expreeFee)) {
            if (expreeFee.compareTo(0) == 1) {
                fee = expreeFee;
            } else {
                fee = postageTemplate.getPrice().intValue();
            }

        } else {
            fee = postageTemplate.getPrice().intValue();
        }
        res.put("fee", fee);
        res.put("extraFee", extraFee);
        return res;
    }

    @Override
    public Map<String, String> placeOrder(PlaceOrderReq req) {
        return null;
    }

    @Override
    public boolean handlePayNotify(OrderPO orderPO) {
        return false;
    }

    /**
     * 校验是否重复下单
     *
     * @param req
     * @param userPO
     */
    private void checkDuplicateOrder(PlaceOrderVO req, UserPO userPO) {
        String activityId = req.getActivityId();
        String caType = req.getCaType();
        String caLevel = req.getCaLevel();

        log.info("【重复下单】checkDuplicateOrder start 校验 userId-> {} caType->{} activityId ->{} caLevel ->{}",
                userPO.getId(), caType,
                activityId, caLevel);
        Query query = new Query();
        query.addCriteria(Criteria.where("accountInfoId").is(userPO.getId()));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("taskBizType").is(caType));
        query.addCriteria(Criteria.where("status").in("1", "2", "3", "4", "5"));
        List<OrderInfo> orderInfoList = this.mongoTemplate.find(query, OrderInfo.class);
        if (!CollectionUtils.isEmpty(orderInfoList)) {
            log.warn("【重复下单】checkDuplicateOrder 未下单 userId-> {} caType->{} activityId ->{} caLevel ->{}",
                    userPO.getId(), caType, activityId, caLevel);
            return;
        }
        List<String> orderNoList = orderInfoList.stream().map(OrderInfo::getOrderNo).collect(Collectors.toList());
        log.info("【重复下单】checkDuplicateOrder 购买证书类型订单 userId-> {} caType->{} activityId ->{} orderNumber ->{}",
                userPO.getId(), caType, activityId, orderNoList.size());
        query = new Query();
        query.addCriteria(Criteria.where("orderNo").in(orderNoList));
        query.addCriteria(Criteria.where("accountInfoId").is(userPO.getId()));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        List<OOrderInfo> subOrderList = this.mongoTemplate.find(query, OOrderInfo.class);
        if (CollectionUtils.isEmpty(subOrderList)) {
            log.warn("【重复下单】checkDuplicateOrder 非法订单未有子订单 userId-> {} caType->{} activityId ->{} caLevel ->{}",
                    userPO.getId(), caType, activityId, caLevel);
            return;
        }
        subOrderList.stream().forEach(subOrderInfo -> {
            long count =
                    req.getCaIds().stream().filter(caInfoId -> subOrderInfo.getItemInfoId().equals(caInfoId)).count();
            if (count > 0) {
                log.error("【重复下单】checkDuplicateOrder 重复下单 userId-> {} caType->{} activityId ->{} caLevel ->{}",
                        userPO.getId(), caType, activityId, caLevel);
                throw new BusinessException("亲，您已购买重该类型等级订单，勿重复下单，感谢您的支持！");
            }
        });
    }
}
